package tasks

import (
	"context"
	"encoding/json"
	"fmt"
	"sync"
	"time"

	log "github.com/sirupsen/logrus"
)

// Status 任务状态
type Status string

const (
	StatusPending   Status = "pending"
	StatusRunning   Status = "running"
	StatusCompleted Status = "completed"
	StatusFailed    Status = "failed"
	StatusRetrying  Status = "retrying"
)

// Task 任务定义
type Task struct {
	ID          string                 `json:"id"`
	Type        string                 `json:"type"`
	Status      Status                 `json:"status"`
	Payload     map[string]interface{} `json:"payload"`
	Result      map[string]interface{} `json:"result,omitempty"`
	Error       string                 `json:"error,omitempty"`
	RetryCount  int                    `json:"retry_count"`
	MaxRetries  int                    `json:"max_retries"`
	CreatedAt   time.Time              `json:"created_at"`
	StartedAt   *time.Time             `json:"started_at,omitempty"`
	CompletedAt *time.Time             `json:"completed_at,omitempty"`
}

// Handler 任务处理器函数
type Handler func(ctx context.Context, task *Task) error

// Queue 任务队列
type Queue struct {
	tasks    map[string]*Task
	handlers map[string]Handler
	pending  chan string
	mu       sync.RWMutex
	store    Store
	workers  int
	stopChan chan struct{}
	wg       sync.WaitGroup
}

// Store 任务持久化存储接口
type Store interface {
	Save(task *Task) error
	Get(id string) (*Task, error)
	List(status Status) ([]*Task, error)
	Delete(id string) error
}

// NewQueue 创建任务队列
func NewQueue(workers int, store Store) *Queue {
	return &Queue{
		tasks:    make(map[string]*Task),
		handlers: make(map[string]Handler),
		pending:  make(chan string, 1000),
		workers:  workers,
		store:    store,
		stopChan: make(chan struct{}),
	}
}

// RegisterHandler 注册任务类型处理器
func (q *Queue) RegisterHandler(taskType string, handler Handler) {
	q.mu.Lock()
	defer q.mu.Unlock()
	q.handlers[taskType] = handler
	log.Infof("Registered handler for task type: %s", taskType)
}

// Submit 提交新任务
func (q *Queue) Submit(taskType string, payload map[string]interface{}, maxRetries int) (*Task, error) {
	task := &Task{
		ID:         generateTaskID(),
		Type:       taskType,
		Status:     StatusPending,
		Payload:    payload,
		MaxRetries: maxRetries,
		CreatedAt:  time.Now(),
	}

	q.mu.Lock()
	q.tasks[task.ID] = task
	q.mu.Unlock()

	// 持久化
	if q.store != nil {
		if err := q.store.Save(task); err != nil {
			log.Errorf("Failed to save task %s: %v", task.ID, err)
		}
	}

	// 加入待处理队列
	select {
	case q.pending <- task.ID:
		log.Infof("Task %s (%s) submitted", task.ID, taskType)
	default:
		return nil, fmt.Errorf("task queue is full")
	}

	return task, nil
}

// Get 获取任务信息
func (q *Queue) Get(id string) (*Task, error) {
	q.mu.RLock()
	task, ok := q.tasks[id]
	q.mu.RUnlock()

	if !ok {
		// 尝试从持久化存储读取
		if q.store != nil {
			return q.store.Get(id)
		}
		return nil, fmt.Errorf("task not found: %s", id)
	}

	return task, nil
}

// List 列出指定状态的任务
func (q *Queue) List(status Status) []*Task {
	q.mu.RLock()
	defer q.mu.RUnlock()

	var result []*Task
	for _, task := range q.tasks {
		if status == "" || task.Status == status {
			result = append(result, task)
		}
	}
	return result
}

// Start 启动任务队列处理
func (q *Queue) Start(ctx context.Context) {
	log.Infof("Starting task queue with %d workers", q.workers)

	// 启动工作协程
	for i := 0; i < q.workers; i++ {
		q.wg.Add(1)
		go q.worker(ctx, i)
	}

	// 加载未完成的任务
	if q.store != nil {
		q.loadPendingTasks()
	}
}

// Stop 停止任务队列
func (q *Queue) Stop() {
	log.Info("Stopping task queue...")
	close(q.stopChan)
	close(q.pending)
	q.wg.Wait()
	log.Info("Task queue stopped")
}

// worker 工作协程
func (q *Queue) worker(ctx context.Context, id int) {
	defer q.wg.Done()
	log.Infof("Worker %d started", id)

	for {
		select {
		case <-ctx.Done():
			log.Infof("Worker %d stopped (context cancelled)", id)
			return
		case <-q.stopChan:
			log.Infof("Worker %d stopped", id)
			return
		case taskID, ok := <-q.pending:
			if !ok {
				log.Infof("Worker %d stopped (channel closed)", id)
				return
			}
			q.processTask(ctx, taskID)
		}
	}
}

// processTask 处理单个任务
func (q *Queue) processTask(ctx context.Context, taskID string) {
	task, err := q.Get(taskID)
	if err != nil {
		log.Errorf("Failed to get task %s: %v", taskID, err)
		return
	}

	// 获取处理器
	q.mu.RLock()
	handler, ok := q.handlers[task.Type]
	q.mu.RUnlock()

	if !ok {
		q.updateTaskStatus(task, StatusFailed, fmt.Errorf("no handler for task type: %s", task.Type))
		return
	}

	// 更新状态为运行中
	now := time.Now()
	task.StartedAt = &now
	task.Status = StatusRunning
	q.saveTask(task)

	log.Infof("Processing task %s (type: %s, attempt: %d/%d)",
		task.ID, task.Type, task.RetryCount+1, task.MaxRetries+1)

	// 执行任务
	err = handler(ctx, task)

	if err != nil {
		task.RetryCount++

		// 判断是否需要重试
		if task.RetryCount < task.MaxRetries {
			log.Warnf("Task %s failed (attempt %d/%d): %v, will retry",
				task.ID, task.RetryCount, task.MaxRetries, err)

			task.Status = StatusRetrying
			task.Error = err.Error()
			q.saveTask(task)

			// 延迟后重新加入队列
			go func() {
				delay := time.Duration(task.RetryCount) * time.Second * 5
				time.Sleep(delay)

				select {
				case q.pending <- taskID:
					log.Infof("Task %s requeued for retry", taskID)
				case <-q.stopChan:
				}
			}()
		} else {
			// 超过最大重试次数
			log.Errorf("Task %s failed after %d attempts: %v",
				task.ID, task.RetryCount, err)
			q.updateTaskStatus(task, StatusFailed, err)
		}
	} else {
		// 任务成功
		log.Infof("Task %s completed successfully", task.ID)
		q.updateTaskStatus(task, StatusCompleted, nil)
	}
}

// updateTaskStatus 更新任务状态
func (q *Queue) updateTaskStatus(task *Task, status Status, err error) {
	now := time.Now()
	task.Status = status
	task.CompletedAt = &now

	if err != nil {
		task.Error = err.Error()
	}

	q.saveTask(task)
}

// saveTask 保存任务
func (q *Queue) saveTask(task *Task) {
	q.mu.Lock()
	q.tasks[task.ID] = task
	q.mu.Unlock()

	if q.store != nil {
		if err := q.store.Save(task); err != nil {
			log.Errorf("Failed to save task %s: %v", task.ID, err)
		}
	}
}

// loadPendingTasks 加载未完成的任务
func (q *Queue) loadPendingTasks() {
	log.Info("Loading pending tasks from storage...")

	statuses := []Status{StatusPending, StatusRunning, StatusRetrying}
	for _, status := range statuses {
		tasks, err := q.store.List(status)
		if err != nil {
			log.Errorf("Failed to load tasks with status %s: %v", status, err)
			continue
		}

		for _, task := range tasks {
			q.mu.Lock()
			q.tasks[task.ID] = task
			q.mu.Unlock()

			// 重置运行中的任务为待处理
			if task.Status == StatusRunning {
				task.Status = StatusPending
			}

			select {
			case q.pending <- task.ID:
				log.Infof("Loaded task %s (%s)", task.ID, task.Type)
			default:
				log.Warnf("Failed to queue task %s: queue is full", task.ID)
			}
		}
	}
}

// Delete 删除任务
func (q *Queue) Delete(id string) error {
	q.mu.Lock()
	defer q.mu.Unlock()

	// 从内存中删除
	delete(q.tasks, id)

	// 从存储中删除
	if q.store != nil {
		if err := q.store.Delete(id); err != nil {
			log.Errorf("Failed to delete task %s from store: %v", id, err)
			// 不返回错误，因为内存中已经删除了
		}
	}

	return nil
}

// generateTaskID 生成任务 ID
func generateTaskID() string {
	return fmt.Sprintf("task_%d", time.Now().UnixNano())
}

// MemoryStore 内存存储实现（用于测试/简单场景）
type MemoryStore struct {
	tasks map[string]*Task
	mu    sync.RWMutex
}

// NewMemoryStore 创建内存存储
func NewMemoryStore() *MemoryStore {
	return &MemoryStore{
		tasks: make(map[string]*Task),
	}
}

func (s *MemoryStore) Save(task *Task) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	// 深拷贝
	data, err := json.Marshal(task)
	if err != nil {
		return err
	}

	var copied Task
	if err := json.Unmarshal(data, &copied); err != nil {
		return err
	}

	s.tasks[task.ID] = &copied
	return nil
}

func (s *MemoryStore) Get(id string) (*Task, error) {
	s.mu.RLock()
	defer s.mu.RUnlock()

	task, ok := s.tasks[id]
	if !ok {
		return nil, fmt.Errorf("task not found")
	}
	return task, nil
}

func (s *MemoryStore) List(status Status) ([]*Task, error) {
	s.mu.RLock()
	defer s.mu.RUnlock()

	var result []*Task
	for _, task := range s.tasks {
		if status == "" || task.Status == status {
			result = append(result, task)
		}
	}
	return result, nil
}

func (s *MemoryStore) Delete(id string) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	delete(s.tasks, id)
	return nil
}
